package com.artisan.requestbodycache.aspect;

import com.artisan.requestbodycache.wrapper.CachedHttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.nio.charset.StandardCharsets;

/**
 * 请求日志切面
 * 演示：在 Controller 执行前后记录请求和响应信息
 * 优势：即使在切面中读取了 Body，Controller 依然可以正常获取
 */
@Aspect
@Component
public class RequestLogAspect {

    private static final Logger log = LoggerFactory.getLogger(RequestLogAspect.class);

    /**
     * 环绕通知：拦截所有 Controller 方法
     */
    @Around("execution(* com.artisan.requestbodycache.controller..*.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        // 获取请求对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return joinPoint.proceed();
        }

        HttpServletRequest request = attributes.getRequest();

        // 记录请求信息
        logRequest(request, joinPoint);

        // 执行目标方法
        Object result = null;
        Throwable exception = null;
        try {
            result = joinPoint.proceed();
            return result;
        } catch (Throwable e) {
            exception = e;
            throw e;
        } finally {
            // 记录响应信息
            long duration = System.currentTimeMillis() - startTime;
            logResponse(request, result, exception, duration);
        }
    }

    /**
     * 记录请求信息（包括 Body）
     */
    private void logRequest(HttpServletRequest request, ProceedingJoinPoint joinPoint) {
        try {
            String method = request.getMethod();
            String uri = request.getRequestURI();
            String queryString = request.getQueryString();
            String fullUrl = queryString != null ? uri + "?" + queryString : uri;

            log.info("========== 请求开始 ==========");
            log.info("方法: {} {}", method, fullUrl);
            log.info("Controller: {}.{}", 
                joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName());
            log.info("客户端IP: {}", getClientIp(request));

            // 关键：读取 Request Body（得益于 CachedHttpServletRequest，可以多次读取）
            if (request instanceof CachedHttpServletRequest) {
                CachedHttpServletRequest cachedRequest = (CachedHttpServletRequest) request;
                byte[] bodyBytes = cachedRequest.getBodyCache();
                if (bodyBytes != null && bodyBytes.length > 0) {
                    String body = new String(bodyBytes, StandardCharsets.UTF_8);
                    log.info("请求体: {}", body.length() > 500 ? body.substring(0, 500) + "..." : body);
                }
            } else {
                log.warn("⚠️  请求未被缓存，无法读取 Body（请检查 CacheRequestFilter 是否生效）");
            }

        } catch (Exception e) {
            log.error("记录请求信息失败", e);
        }
    }

    /**
     * 记录响应信息
     */
    private void logResponse(HttpServletRequest request, Object result, Throwable exception, long duration) {
        try {
            if (exception != null) {
                log.error("========== 请求异常 ==========");
                log.error("异常类型: {}", exception.getClass().getName());
                log.error("异常信息: {}", exception.getMessage());
                log.error("耗时: {} ms", duration);
            } else {
                log.info("========== 请求结束 ==========");
                if (result != null) {
                    String resultStr = result.toString();
                    log.info("响应结果: {}", resultStr.length() > 200 ? resultStr.substring(0, 200) + "..." : resultStr);
                }
                log.info("耗时: {} ms", duration);
            }
        } catch (Exception e) {
            log.error("记录响应信息失败", e);
        }
    }

    /**
     * 获取客户端真实 IP
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 处理多个代理的情况
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }
        return ip;
    }
}

